package com.rm.zeyou.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rm.zeyou.constant.CommonConstants;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.entity.*;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.*;
import com.rm.zeyou.pay.wxpay.constants.WechatPayOutConstants;
import com.rm.zeyou.pay.wxpay.transfer.service.TransferNewService;
import com.rm.zeyou.pay.wxpay.transfer.vo.TransferQueryResponse;
import com.rm.zeyou.response.ApiRestResponse;
import com.rm.zeyou.service.TechnicianPayoutDetailService;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.vo.request.SelectUserPayoutIndexVo;
import com.rm.zeyou.vo.response.ConfirmPayoutResponseVo;
import com.rm.zeyou.vo.response.SelectUserPayoutIndexResponseVo;
import com.rm.zeyou.vo.response.UserPayoutVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 用户提现表 服务实现类
 * </p>
 *
 * @author YanYang
 * @since 2025-03-12 15:55:09
 */
@Service
public class TechnicianPayoutDetailServiceImpl extends ServiceImpl<TechnicianPayoutDetailMapper, TechnicianPayoutDetail> implements TechnicianPayoutDetailService {
    @Resource
    private TechnicianConsumeDetailMapper technicianConsumeDetailMapper;
    @Resource
    private TechnicianBackMapper technicianBackMapper;
    @Resource
    private PayoutConfigMapper payoutConfigMapper;
    @Resource
    private TechnicianPayoutDetailMapper technicianPayoutDetailMapper;
    @Resource
    private TechnicianZfbCountMapper technicianZfbCountMapper;
    @Resource
    private AgreementConfigMapper agreementConfigMapper;
    @Resource
    private PayoutDictConfigMapper payoutDictConfigMapper;
    @Resource
    private TransferNewService transferNewService;
    @Resource
    private WxpayConfigMapper wxpayConfigMapper;
    @Resource
    private ApplicationConfigMapper applicationConfigMapper;

    @Override
    public ApiRestResponse<SelectUserPayoutIndexResponseVo> selectTechnicianPayoutIndex(Technician technician, SelectUserPayoutIndexVo requestVo) {
        SelectUserPayoutIndexResponseVo responseVo = new SelectUserPayoutIndexResponseVo();
        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));

        responseVo.setMinPayoutPrice(minPayoutPrice);
        responseVo.setMaxPayoutPrice(maxPayoutPrice);
        // 收入金额
        BigDecimal addAmount = technicianConsumeDetailMapper.selectAddAmount(technician.getId(), NumberConstants.ONE_CONSTANTS);
        //已提现金额
        BigDecimal payoutAmount = technicianConsumeDetailMapper.selectPayoutAmount(technician.getId());
        //可提现金额
        BigDecimal canPayoutAmount = addAmount.subtract(payoutAmount);
        responseVo.setUserBalance(canPayoutAmount);
        responseVo.setTaxPrice(requestVo.getPayoutPrice().multiply(payoutTax));
        responseVo.setFeePrice(requestVo.getPayoutPrice().multiply(payoutFee));

        int userBackCount = technicianBackMapper.selectCount(new LambdaQueryWrapper<TechnicianBack>()
                .eq(TechnicianBack::getTid, technician.getId())).intValue();
        if (userBackCount > 0) {
            responseVo.setIsBindBack(NumberConstants.ONE_CONSTANTS);
        } else {
            responseVo.setIsBindBack(NumberConstants.ZERO_CONSTANTS);
        }

        if (CheckEmptyUtil.isEmpty(technician.getOpenId())) {
            responseVo.setIsBindWx(NumberConstants.ZERO_CONSTANTS);
        } else {
            responseVo.setIsBindWx(NumberConstants.ONE_CONSTANTS);
        }

        TechnicianZfbCount technicianZfbCount = technicianZfbCountMapper.selectOne(new LambdaQueryWrapper<TechnicianZfbCount>().eq(TechnicianZfbCount::getTid, technician.getId()));
        if (CheckEmptyUtil.isEmpty(technicianZfbCount)) {
            responseVo.setIsBindZfb(NumberConstants.ZERO_CONSTANTS);
        } else {
            responseVo.setIsBindZfb(NumberConstants.ONE_CONSTANTS);
        }
        String payoutIllustrate = agreementConfigMapper.selectValue("payout_illustrate");
        responseVo.setPayoutIllustrate(payoutIllustrate);

        return ApiRestResponse.success(responseVo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> technicianPayout(Technician technician, UserPayoutVo requestVo) {
        PayoutConfig payoutConfig = payoutConfigMapper.selectById(requestVo.getPayoutWayId());
        if (CheckEmptyUtil.isEmpty(payoutConfig) && requestVo.getPayoutWayId() !=4) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_WAY_EMPTY);
        }
        if (requestVo.getPayoutWayId() == 4) {
            TechnicianBack technicianBack = technicianBackMapper.selectById(requestVo.getUserBackId());
            if (CheckEmptyUtil.isEmpty(technicianBack)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_BACK_EMPTY);
            }
        }
        if (requestVo.getPayoutWayId() == 3) {
            TechnicianZfbCount userZfbCount = technicianZfbCountMapper.selectOne(new LambdaQueryWrapper<TechnicianZfbCount>().eq(TechnicianZfbCount::getTid, technician.getId()));
            if (CheckEmptyUtil.isEmpty(userZfbCount)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ZFB_COUNT_EMPTY);
            }
        }

        if (requestVo.getPayoutWayId() == 2) {
            String openId;
            if (requestVo.getWithdrawalsEnvironment().equals("H5")) {
                openId = technician.getH5OpenId();
            } else {
                openId = technician.getOpenId();
            }
            if (CheckEmptyUtil.isEmpty(openId)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
            }
        }

        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));

        if (requestVo.getPayoutPrice().compareTo(minPayoutPrice) < 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }

        if (requestVo.getPayoutPrice().compareTo(maxPayoutPrice) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }
        // 收入金额
        BigDecimal addAmount = technicianConsumeDetailMapper.selectAddAmount(technician.getId(), NumberConstants.ONE_CONSTANTS);
        //已提现金额
        BigDecimal payoutAmount = technicianConsumeDetailMapper.selectPayoutAmount(technician.getId());
        //可提现金额
        BigDecimal canPayoutAmount = addAmount.subtract(payoutAmount);
        if (requestVo.getPayoutPrice().compareTo(canPayoutAmount) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_PRICE_ENOUGH);
        }

        TechnicianPayoutDetail technicianPayoutDetail = new TechnicianPayoutDetail();
        technicianPayoutDetail.setTid(technician.getId());
        technicianPayoutDetail.setPayoutType(Math.toIntExact(requestVo.getPayoutWayId()));
        technicianPayoutDetail.setPayoutPrice(requestVo.getPayoutPrice());
        BigDecimal fee = requestVo.getPayoutPrice().multiply(payoutFee);
        technicianPayoutDetail.setPremium(fee);
        BigDecimal tax = requestVo.getPayoutPrice().multiply(payoutTax);
        technicianPayoutDetail.setPayoutTax(tax);
        technicianPayoutDetail.setRealPrice(requestVo.getPayoutPrice().subtract(fee).subtract(tax));
        if (requestVo.getPayoutWayId() == 4) {
            TechnicianBack technicianBack = technicianBackMapper.selectById(requestVo.getUserBackId());
            technicianPayoutDetail.setBackName(technicianBack.getBackName());
            technicianPayoutDetail.setBackUserName(technicianBack.getBackUserName());
            technicianPayoutDetail.setBackIdcard(technicianBack.getBackIdcard());
            technicianPayoutDetail.setBackBranch(technicianBack.getBackBranch());
        }
        technicianPayoutDetail.setWithdrawalsEnvironment(requestVo.getWithdrawalsEnvironment());
        technicianPayoutDetailMapper.insert(technicianPayoutDetail);


        TechnicianConsumeDetail technicianConsumeDetail = new TechnicianConsumeDetail();
        technicianConsumeDetail.setTid(technician.getId());
        technicianConsumeDetail.setTechnicianPayoutId(technicianPayoutDetail.getId());
        technicianConsumeDetail.setPayoutPrice(requestVo.getPayoutPrice());
        technicianConsumeDetail.setConsumeType(CommonConstants.CONSUMPTION_PAYOUT);
        technicianConsumeDetail.setConsumptionDescribe("提现审核中");
        int insert = technicianConsumeDetailMapper.insert(technicianConsumeDetail);


        return ApiRestResponse.success(insert);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void updateTechnicianWithdrawals() {
        List<TechnicianPayoutDetail> technicianPayoutDetails = technicianPayoutDetailMapper.selectNotSuccessOrFailList();
        if (!CheckEmptyUtil.isEmpty(technicianPayoutDetails)) {
            for (TechnicianPayoutDetail technicianPayoutDetail : technicianPayoutDetails) {
                TransferQueryResponse transferQueryResponse = transferNewService.queryTransferByOutBillNo(technicianPayoutDetail.getWxWithdrawalsNo());
                if (!CheckEmptyUtil.isEmpty(transferQueryResponse)) {
                    technicianPayoutDetail.setWxWithdrawalsStatus(transferQueryResponse.getState());
                    TechnicianConsumeDetail technicianConsumeDetail = technicianConsumeDetailMapper.selectOne(new LambdaQueryWrapper<TechnicianConsumeDetail>()
                            .eq(TechnicianConsumeDetail::getTechnicianPayoutId, technicianPayoutDetail.getId()));
                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.SUCCESS)) {
                        technicianPayoutDetail.setPayoutStatus(NumberConstants.ONE_CONSTANTS);
                        technicianConsumeDetail.setConsumptionDescribe("提现成功");
                    }

                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.FAIL)) {
                        technicianPayoutDetail.setPayoutStatus(NumberConstants.TWO_CONSTANTS);
                        technicianConsumeDetail.setConsumptionDescribe("提现失败");
                    }
                    technicianPayoutDetailMapper.updateById(technicianPayoutDetail);
                    technicianConsumeDetailMapper.updateById(technicianConsumeDetail);
                }
            }
        }
    }

    @Override
    public ApiRestResponse<List<ConfirmPayoutResponseVo>> technicianConfirmPayout(Technician technician) {
        List<TechnicianPayoutDetail> technicianPayoutDetails = technicianPayoutDetailMapper.selectList(new LambdaQueryWrapper<TechnicianPayoutDetail>()
                .eq(TechnicianPayoutDetail::getWxWithdrawalsStatus, "WAIT_USER_CONFIRM")
                .eq(TechnicianPayoutDetail::getTid, technician.getId()));
        List<ConfirmPayoutResponseVo> responseVoList = new ArrayList<>(technicianPayoutDetails.size());
        if (!CheckEmptyUtil.isEmpty(technicianPayoutDetails)) {
            for (TechnicianPayoutDetail technicianPayoutDetail : technicianPayoutDetails) {
                ConfirmPayoutResponseVo responseVo = new ConfirmPayoutResponseVo();
                responseVo.setId(technicianPayoutDetail.getId());
                responseVo.setPackageInfo(technicianPayoutDetail.getPackageInfo());
                String mchId = wxpayConfigMapper.selectOneData("mchId");
                String accountAppid = applicationConfigMapper.selectOneData("account_appid");
                responseVo.setH5Appid(accountAppid);
                String appAppid = applicationConfigMapper.selectOneData("app_appid");
                responseVo.setAppAppid(appAppid);
                responseVo.setMuchId(mchId);
                responseVoList.add(responseVo);
            }
        }
        return ApiRestResponse.success(responseVoList);
    }
}
